using System;
using System.Collections.Generic;
using System.Text;
using OB;
using OpenTK.Math;

namespace raycaster
{
  public class Triangle
  {
    Vector3 p1, p2, p3;

    public Triangle(Vector3 p1, Vector3 p2, Vector3 p3)
    {
      this.p1 = p1;
      this.p2 = p2;
      this.p3 = p3;
    }

    public static void SelfTest(ITestToolkit tk) {
      Triangle t = new Triangle(Vector3.UnitX, Vector3.UnitY, Vector3.UnitZ);
      Ray r = new Ray(new Vector3(0.1f, 0.1f, 3), new Vector3(0, 0, -1));
      IntersectionResult result = t.Intersect(r);
      tk.Assert(result.DoesIntersect);

      t = new Triangle(Vector3.Zero, Vector3.UnitX, Vector3.UnitY);
      r = new Ray(new Vector3(0.1f, 0.1f, 3), -Vector3.UnitZ);
      result = t.Intersect(r);
      tk.AssertEqual(3, result.Param);

      r = new Ray(new Vector3(-1, 0, 3), -Vector3.UnitZ);
      result = t.Intersect(r);
      tk.Assert(!result.DoesIntersect);
    }

    public IntersectionResult Intersect(Ray r)
    {
      Vector3 p2p1 = p2 - p1;
      Vector3 p3p1 = p3 - p1;
      Vector3 triNormal = Vector3.Cross(p2p1, p3p1);
      triNormal.Normalize();
      float dot = Vector3.Dot(r.Direction, triNormal);
      if (Calc.AlmostZero(dot))
        return IntersectionResult.NoIntersection;
      else
      {
        float d = Vector3.Dot(triNormal, p1);
        float np4 = Vector3.Dot(triNormal, r.Origin);
        float nv = Vector3.Dot(triNormal, r.Direction);
        float t = (d - np4) / nv;

        Vector3 q = r.Origin + r.Direction * t;

        float a = Vector3.Dot(Vector3.Cross(p2p1, q - p1), triNormal);
        float b = Vector3.Dot(Vector3.Cross(p3 - p2, q - p2), triNormal);
        float c = Vector3.Dot(Vector3.Cross(p1 - p3, q - p3), triNormal);
        if (a >= 0 && b >= 0 && c >= 0)
          return IntersectionResult.Interects(t);
        else
          return IntersectionResult.NoIntersection;
      }
    }
  }
}
